package co.fitstart.admin.handler.impl;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.demo2do.core.BusinessException;

import co.fitstart.admin.handler.ZipHandler;
import co.fitstart.admin.handler.support.FileStorage;
import co.fitstart.entity.course.round.CourseRound;
import co.fitstart.entity.user.User;

/**
 * 
 * @author mohanlan
 *
 */
@Component("zipHandler")
public class ZipHandlerImpl implements ZipHandler {
    
    private static final Logger logger = LoggerFactory.getLogger(ZipHandlerImpl.class);
    
    @Value("#{config['file.upload.path']}")
    private String uploadPath;
    
    static final int BUFFER = 8192;
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.handler.ZipHandler#zipFile(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.util.Map)
     */
    public void zipFile(String path, String filename, String targetFolder, String zipname,
            Map<String, List<CourseRound>> rounds) throws Exception {
        
          FileOutputStream fOutputStream = this.initZip(path, filename, targetFolder, zipname);
          ZipOutputStream zoutput = new ZipOutputStream(fOutputStream);
          
          List<String> fileNames = new ArrayList<String>();
          for (String key : rounds.keySet()) {
              for (CourseRound courseRound : rounds.get(key)) {
                  
                  User user = courseRound.getStudent().getUser();
                  // validate user could save order qrcode or not
                  if(!this.validateUser(user)) {
                      throw new BusinessException("用户数据异常");
                  }
                  
                  InputStream inputStream = this.getUserQrcodeFile(user);
                  
                  FileStorage fileStorage = this.generateOrderFileStorage(courseRound, key);
                  String qrcodeName = fileStorage.getPath() + "/" + fileStorage.getFileName();
                  
                  // if this fileName not exsit int zip add file
                  if(!fileNames.contains(qrcodeName)) {
                      this.writeFile(zoutput, inputStream, qrcodeName);
                      fileNames.add(qrcodeName);
                  }
                  
              }
          }
          
          zoutput.closeEntry();
          zoutput.close();
          fOutputStream.close();
        
    }
    
    /**
     * 
     * @param user
     * @return
     */
    private boolean validateUser(User user) {
        
        if(user.getWechat() == null || StringUtils.isEmpty(user.getWechat().getCode()) || StringUtils.isEmpty(user.getWechat().getQrcode())) {
            logger.trace("user wechat code or wechat qrcode not exit, do not save qrcode into order package");
            return false;
        }
        
        if(user.getUserFit() == null || user.getUserFit().getHeight() == null || user.getUserFit().getWeight() == null || user.getUserFit().getBmiValue() == null) {
            logger.trace("user fit weight height bmi not exit, do not save qrcode into order package");
            return false;
        }
        
        return true;
    }
    
    /**
     * 
     * @param path
     * @param filename
     * @param targetFolder
     * @param zipname
     * @return
     * @throws Exception
     */
    private FileOutputStream initZip(String path, String filename, String targetFolder, String zipname) throws Exception{
        String zipFullName = targetFolder == null ? (path == null ? zipname : (path + "/" + zipname)) : (targetFolder + "/" + zipname);
        
        File file = new File(zipFullName + ".zip");
        if(!file.exists()) {
            file.createNewFile();
            logger.trace("#initZip - create zip file with name [{name}]", file.getName());
        }
        
        FileOutputStream fOutputStream = new FileOutputStream(file);
        return fOutputStream;
    }
    
    /**
     * 
     * @param zoutput
     * @param inputStream
     * @param qrcodeName
     * @throws IOException
     */
    private void writeFile(ZipOutputStream zoutput, InputStream inputStream, String qrcodeName) throws IOException {
        // put file to zip
        zoutput.putNextEntry(new ZipEntry(qrcodeName));
        logger.trace("#writeFile - put file into zipFile with name [{qrcodeName}]", qrcodeName);
        
        BufferedInputStream bis = new BufferedInputStream(inputStream);
        
        int count;
        byte data[] = new byte[BUFFER];
        while ((count = bis.read(data, 0, BUFFER)) != -1) {  
                zoutput.write(data, 0, count);  
        }  
        logger.trace("#writeFile - write qrcode image to zip");
        bis.close();
    }
    
    /**
     * 
     * @param user
     * @return
     */
    private InputStream getUserQrcodeFile(User user) {
        
        InputStream inputStream;
        
        try {
            
            String wechatCode = user.getWechat().getCode();
            String fileName = org.apache.commons.lang3.StringUtils.replace(wechatCode, " ", "-");
            fileName = StringUtils.replace(fileName, ".", "-");
            
            logger.info("#getUserQrcodeFile() start get user qrcode file with fileName[{}] userName [{}] userMobile [{}]", fileName,user.getName(),user.getMobile());
            
            File qrcode = new File(uploadPath + "/user/qrcode/" + fileName, fileName + ".jpg");
            inputStream = new FileInputStream(qrcode);
            
        } catch (FileNotFoundException e) {
            logger.error("#getUserQrcodeFile() error [{}]",e);
            throw new BusinessException("获取用户二维码失败");
        }
        
        return inputStream;
    }
    
    /**
     * 
     * @param courseRound
     * @param groupName
     * @return
     */
    private FileStorage generateOrderFileStorage(CourseRound courseRound, String groupName) {
        
        String filename = org.apache.commons.lang3.StringUtils.replace(courseRound.getOrder().getProduct().getName(), " ", "-");
        
        String filePath = filename + "/" + groupName + "/" + courseRound.getOnlineRoundAttr().getZipName();
        
        logger.info("generateOrderFileStorage# generate fileStorage with fileName [{}] and filePath [{}]", filename, filePath);
        FileStorage fileStorage = new FileStorage(filePath, courseRound.getStudent().getUser().getMobile(), "jpg");
        
        return fileStorage;
    }

}
